using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Navigation;
using JurnalUmum.CoaServices;
using JurnalUmum.DepartemenServices;
using JurnalUmum.JurnalServices;
using JurnalUmum.PurchaseInvoiceServices;
using JurnalUmum.SalesInvoiceServices;
using Lib;
using Lib.Helper;
using MSIACCSL2.Command;
using WcfService1.DTO;
using GetListByCriteriaCompletedEventArgs = JurnalUmum.JurnalServices.GetListByCriteriaCompletedEventArgs;
using GetListCompletedEventArgs = JurnalUmum.JurnalServices.GetListCompletedEventArgs;
using SaveCompletedEventArgs = JurnalUmum.JurnalServices.SaveCompletedEventArgs;

namespace JurnalUmum.ViewModels
{
    public class JurnalAllViewModel : ViewModelBase
    {
        #region Delegates

        public delegate void Completed(Object param);

        #endregion

        private static string OrderType;
        private static string PropertySort;
        public static Mode mode;
        private static FrmAdd frmAdd;
        private static NavigationService _NavigationService;
        public static Completed OnSearchCompleted;


        private readonly JurnalServicesClient client;
        private readonly DepartemenServices.DepartemenServicesClient CostClient;
        private readonly SalesInvoiceServices.SalesInvoiceServicesClient siClient;
        private readonly PurchaseInvoiceServices.PurchaseInvoiceServicesClient piClient;
        private readonly ValidationHandler validationHandler;
        private int CurrentPage;
        private ObservableCollection<int> Pages;
        private bool _IsBusy;
        private JurnalDTO _Jurnal;
        private PagedCollectionView _Jurnals;
        private List<string> _errors;
        private Visibility _messageVisibility;
        private PagedCollectionView _pageSources;
        private string expression;
        private ObservableCollection<DepartemenDTO> _Departemens;
        private ObservableCollection<string> _Tipes;


        public JurnalAllViewModel()
        {
            if (!DesignerProperties.IsInDesignTool)
            {
                client = new JurnalServicesClient();
                CostClient = new DepartemenServicesClient();
                siClient = new SalesInvoiceServicesClient();
                piClient = new PurchaseInvoiceServicesClient();
                OnPageChanged = new DelegateCommand(PageIndexChanged, CanPageIndexChanged);
                Save = new DelegateCommand(SaveJurnal, CanSave);
                New = new DelegateCommand(NewJurnal, CanNew);
                Unload = new DelegateCommand(Release, CanUnload);
                SearchCommand = new DelegateCommand(SearchJurnal, CanSearch);
                SearchResultCommand = new DelegateCommand(SearchResult, CanSearchResult);
                CancelCommand = new DelegateCommand(Cancel, CanCancelCommand);
                //GetLastNumberCommand = new DelegateCommand(GetLastNoJurnal,CanGetLastNumber);
                validationHandler = new ValidationHandler();
                MessageVisibility = Visibility.Collapsed;

                if (mode == Mode.Edit)
                {
                   PrepareEdit();
                }
                else if (mode == Mode.Search)
                {
                    Jurnal = new JurnalDTO();
                }
                else if (mode == Mode.Add)
                {
                    PrepareAdd();
                }
                else
                {
                    GetList(1, null);
                }
            }
        }

        public void PrepareAdd()
        {
            GetDepartemens();
            Jurnal = new JurnalDTO();
            Jurnal.JurnalDetails = new ObservableCollection<JurnalDetailDTO>();
            var JurnalDetail = new JurnalDetailDTO();
            Jurnal.JurnalDetails.Add(JurnalDetail);
            Tipes = new ObservableCollection<string>();
            Tipes.Add("Umum");
            Tipes.Add("Penyesuaian");
        }

        public void PrepareEdit()
        {
            Jurnal = (JurnalDTO)Navigation.Args;
            GetJurnal(Jurnal.NoVoucher);
            if (Jurnal.JurnalDetails == null)
                Jurnal.JurnalDetails = new ObservableCollection<JurnalDetailDTO>();
            if (Jurnal.JurnalDetails.Count == 0)
                Jurnal.JurnalDetails.Add(new JurnalDetailDTO());
            Tipes = new ObservableCollection<string>();
            Tipes.Add("Umum");
            Tipes.Add("Penyesuaian");
        }

        public void GetJurnal(string noVoucher)
        {
            client.GetJurnalCompleted += client_GetJurnalCompleted;
            client.GetJurnalAsync(noVoucher);
        }

        void client_GetJurnalCompleted(object sender, GetJurnalCompletedEventArgs e)
        {
            client.GetJurnalCompleted -= client_GetJurnalCompleted;
            Jurnal = e.Result;
            GetDepartemens();
        }

        public PagedCollectionView Jurnals
        {
            get { return _Jurnals; }

            private set
            {
                if (Jurnals == value) return;
                _Jurnals = value;
                int i = (CurrentPage*30);
                foreach (object Jurnal in Jurnals)
                {
                    i += 1;

                    ((JurnalDTO) Jurnal).No = i;
                }
                FirePropertyChanged("Jurnals");
                Jurnals.CollectionChanged += Jurnal_CollectionChanged;
            }
        }

        public PagedCollectionView PageSources
        {
            get { return _pageSources; }
            private set
            {
                if (PageSources == value) return;
                _pageSources = value;
                FirePropertyChanged("PageSources");
            }
        }


        public bool IsBusy
        {
            get { return _IsBusy; }
            internal set
            {
                _IsBusy = value;
                FirePropertyChanged("IsBusy");
            }
        }


        public long RecordCount { get; set; }

        //Buat binding ke child form waktu mau edit
        public JurnalDTO Jurnal
        {
            get { return _Jurnal; }
            private set
            {
                if (Jurnal == value) return;
                _Jurnal = value;
                FirePropertyChanged("Jurnal");
            }
        }


        public ObservableCollection<String> Tipes
        {
            get { return _Tipes; }
            private set
            {
                if (ReferenceEquals(_Tipes,value) || value==null) return;
                _Tipes = value;
                FirePropertyChanged("Tipes");
            }
        }


        public ICommand OnPageChanged { get; set; }
        public ICommand Save { get; set; }
        public ICommand New { get; set; }
        public ICommand Edit { get; set; }
        public ICommand Unload { get; set; }
        public ICommand SearchCommand { get; set; }
        public ICommand SearchResultCommand { get; set; }
        public ICommand CancelCommand { get; set; }

        public List<string> Errors
        {
            get { return _errors; }
            private set
            {
                if (Errors == value) return;
                _errors = value;
                FirePropertyChanged("Errors");
            }
        }

        public Visibility MessageVisibility
        {
            get { return _messageVisibility; }
            private set
            {
                if (MessageVisibility == value) return;
                _messageVisibility = value;
                FirePropertyChanged("MessageVisibility");
            }
        }


        public ObservableCollection<DepartemenDTO> Departemens
        {
            get { return _Departemens; }
            private set
            {
                if (Departemens == value) return;
                _Departemens = value;
                FirePropertyChanged("Departemens");
            }
        }

        public string this[string columnName]
        {
            get
            {
                if (validationHandler.BrokenRuleExists(columnName))
                {
                    return validationHandler[columnName];
                }
                return null;
            }
        }

        public void Complete(Object param)
        {
            OnSearchCompleted(param);
        }

        private void Jurnal_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (((PagedCollectionView) sender).SortDescriptions.Count > 0)
            {
                if (((PagedCollectionView) sender).SortDescriptions[0].PropertyName.ToLower() == "no") return;

                PropertySort = ((PagedCollectionView) sender).SortDescriptions[0].PropertyName;
                if (string.IsNullOrEmpty(OrderType))
                {
                    OrderType = "ASC";
                }
                else
                {
                    OrderType = OrderType == "ASC" ? OrderType = "DESC" : OrderType = "ASC";
                }
                GetList(1, PropertySort);
            }
        }


        public void SaveJurnal(Object jurnal)
        {
            Jurnal.ReffNumber = Jurnal.NoVoucher;
            if (Jurnal.JurnalDetails.Count == 1)
            {
                //Bila tidak ada yang dipilih di detail maka details harus dihapus
                if (Jurnal.JurnalDetails[0].Coa == null)
                    Jurnal.JurnalDetails.Clear();
            }
            Validate();
            if (Errors.Count > 0) return;
            //Jurnal.created_by = GlobalVar.User.UserID;
            //Jurnal.modified_by = GlobalVar.User.UserID;
            client.SaveCompleted += client_SaveCompleted;
            client.SaveAsync(Jurnal);
        }

        private void client_SaveCompleted(object sender, SaveCompletedEventArgs e)
        {
            client.SaveCompleted -= client_SaveCompleted;
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
                return;
            }
           
            if (e.Result)
            {
                mode = Mode.Idle;
                Navigation.MyNavigation.Navigate(new Uri("/EXT:JurnalUmum.dll/Index", UriKind.Relative));
            }
        }


        public void GetList(int? page, string sortProp)
        {
            IsBusy = true;
            client.GetListAllCompleted += client_GetListAllCompleted;
            client.GetListAllAsync(page ?? 1, sortProp, OrderType);
        }

        void client_GetListAllCompleted(object sender, GetListAllCompletedEventArgs e)
        {
            client.GetListAllCompleted -= client_GetListAllCompleted;
            RecordCount = e.recordCount;
            if (PageSources == null) CreatePageNumber();
            Jurnals = new PagedCollectionView(e.Result);
            IsBusy = false;
            Complete(this);
        }


        private void NewJurnal(Object param)
        {
            mode = Mode.Add;
            Navigation.MyNavigation = (NavigationService) param;
            Navigation.MyNavigation.Navigate(new Uri("/EXT:JurnalUmum.dll/FrmAdd", UriKind.Relative));
        }


        private void SearchJurnal(Object param)
        {
            mode = Mode.Search;
            Jurnal = new JurnalDTO();
            EventAggregator.PublishMessage("SearchJurnal", null, null);
        }


        private void SearchResult(Object param)
        {
            var criteria = new Dictionary<string, object>();

            foreach (PropertyInfo prop in Jurnal.GetType().GetProperties())
            {
                if (prop.PropertyType == typeof (Decimal))
                {
                    if ((Decimal) prop.GetValue(Jurnal, null) == 0) continue;
                }
                if (prop.PropertyType == typeof (Int32))
                {
                    if ((Int32) prop.GetValue(Jurnal, null) == 0) continue;
                }
                if (prop.PropertyType == typeof (Int64))
                {
                    if ((Int64) prop.GetValue(Jurnal, null) == 0) continue;
                }
                if (prop.PropertyType == typeof (Double))
                {
                    if ((Double) prop.GetValue(Jurnal, null) == 0) continue;
                }
                if (prop.PropertyType == typeof (String))
                {
                    if (String.IsNullOrEmpty((String) prop.GetValue(Jurnal, null))) continue;
                }
                if (prop.PropertyType == typeof (DateTime))
                {
                    if (prop.GetValue(Jurnal, null).ToString().Contains("0001")) continue;
                }
                if (prop.GetValue(Jurnal, null) == null) continue;
                if (prop.PropertyType.Name == "No") continue;
                if (prop.PropertyType.Name.Contains("Collection")) continue;

                if (prop.PropertyType.Name.ToLower().Contains("dto"))
                {
                    foreach (PropertyInfo propertyInfo in prop.GetValue(Jurnal, null).GetType().GetProperties()
                        )
                    {
                        if (propertyInfo.Name.ToLower().Contains("id") || propertyInfo.Name.ToLower().Contains("kode") ||
                            propertyInfo.Name.ToLower().Contains("serial") ||
                            propertyInfo.Name.ToLower().Contains("code"))
                        {
                            criteria.Add(prop.Name, propertyInfo.GetValue(prop.GetValue(Jurnal, null), null));
                            break;
                        }
                    }
                }
                else
                {
                    criteria.Add(prop.Name, prop.GetValue(Jurnal, null));
                }
            }

            expression = string.Empty;
            if (param as bool? ?? false) expression = "OR";
            else expression = "AND";
            JurnalSearch(criteria, expression);
        }

        private void JurnalSearch(Dictionary<String, Object> criteria, string expression)
        {
            IsBusy = true;
            Complete(this);
            client.GetListByCriteriaCompleted += client_GetListByCriteriaCompleted;
            client.GetListByCriteriaAsync(criteria, expression, 1);
        }

        private void client_GetListByCriteriaCompleted(object sender, GetListByCriteriaCompletedEventArgs e)
        {
            client.GetListByCriteriaCompleted -= client_GetListByCriteriaCompleted;
            Jurnals = new PagedCollectionView(e.Result);
            RecordCount = e.recordCount;
            CreatePageNumber();
            IsBusy = false;
        }


        private void CreatePageNumber()
        {
            Pages = new ObservableCollection<int>();
            for (int i = 0; i < RecordCount; i++)
            {
                Pages.Add(i);
            }
            PageSources = new PagedCollectionView(Pages);
        }


        private void PageIndexChanged(Object pageIndex)
        {
            //Jika Pertama kali jangan di Getlagi
            Jurnal = null;
            if (Jurnals != null && CurrentPage != (int) pageIndex)
            {
                CurrentPage = (int) pageIndex;
                if (String.IsNullOrEmpty(PropertySort))
                    GetList((int) pageIndex + 1, null);
                else GetList((int) pageIndex + 1, PropertySort);
            }
        }


        public bool CanPageIndexChanged(Object param)
        {
            return true;
        }


        public bool CanSave(Object param)
        {
            return true;
        }


        public bool CanNew(Object param)
        {
            return true;
        }

        public bool CanEdit(Object param)
        {
            return true;
        }


        public bool CanUnload(Object param)
        {
            return true;
        }


        public bool CanSearch(Object param)
        {
            return true;
        }

        public bool CanSearchResult(Object param)
        {
            return true;
        }

        public bool CanCancelCommand(Object param)
        {
            return true;
        }


        public void Release(Object param)
        {
            param = null;
            Jurnal = null;
            OrderType = null;
            PropertySort = null;
            mode = Mode.Idle;
        }


        public void Refresh()
        {
            if (Jurnals == null)
                GetList(1, null);
            else
                Complete(this);
        }


        public void Validate(string error = null)
        {
            Errors = new List<string>();
        
            if (Jurnal.JurnalDetails.Sum(x => x.Debit) != Jurnal.JurnalDetails.Sum(x => x.Kredit))
            {
                MessageBox.Show("Jurnal tidak balance!");
                Errors.Add("Jurnal tidak balance!");
            }

            if (Errors.Count > 0)
                MessageVisibility = Visibility.Visible;
            else
                MessageVisibility = Visibility.Collapsed;
        }

        public void Cancel(Object param)
        {
            mode = Mode.Idle;
            Navigation.MyNavigation.GoBack();
        }
     
        public void GetDepartemens()
        {
            CostClient.GetAllDepartemenCompleted += new EventHandler<GetAllDepartemenCompletedEventArgs>(CostClient_GetAllDepartemenCompleted);
            CostClient.GetAllDepartemenAsync();
        }

        void CostClient_GetAllDepartemenCompleted(object sender, GetAllDepartemenCompletedEventArgs e)
        {
            CostClient.GetAllDepartemenCompleted -= new EventHandler<GetAllDepartemenCompletedEventArgs>(CostClient_GetAllDepartemenCompleted);
            Departemens = e.Result;
            foreach (var jd in Jurnal.JurnalDetails)
            {
                jd.Departemens = e.Result;
                if (jd.Departemen != null)
                    jd.Departemen = e.Result.FirstOrDefault(x => x.Code == jd.Departemen.Code);
            }
        }

        public ICommand GetLastNumberCommand { get; set; }
        public bool CanGetLastNumber (Object param)
        {
            return true;
        }


        public void LoadSI()
        {
            siClient.GetAllSalesInvoiceCompleted += siClient_GetAllSalesInvoiceCompleted;   
            siClient.GetAllSalesInvoiceAsync();
        }

        void siClient_GetAllSalesInvoiceCompleted(object sender, GetAllSalesInvoiceCompletedEventArgs e)
        {
            siClient.GetAllSalesInvoiceCompleted -= siClient_GetAllSalesInvoiceCompleted;
            foreach (var jd in Jurnal.JurnalDetails)
            {
                jd.IsVisibleSI = Visibility.Visible;
                jd.SalesInvoices = e.Result;
                if (jd.SalesInvoice != null)
                {
                    jd.SalesInvoice = jd.SalesInvoices.FirstOrDefault(x => x.SINo == jd.SalesInvoice.SINo);
                }

            }
        }

        public void LoadPI()
        {
            piClient.GetAllPurchaseInvoiceCompleted += piClient_GetAllPurchaseInvoiceCompleted;
            piClient.GetAllPurchaseInvoiceAsync();
        }

        void piClient_GetAllPurchaseInvoiceCompleted(object sender, GetAllPurchaseInvoiceCompletedEventArgs e)
        {
            piClient.GetAllPurchaseInvoiceCompleted -= piClient_GetAllPurchaseInvoiceCompleted;
            foreach (var jd in Jurnal.JurnalDetails)
            {
                jd.PurchaseInvoices = e.Result;
                jd.IsVisiblePI = Visibility.Visible;
                if (jd.PurchaseInvoice != null)
                {
                    jd.PurchaseInvoice = jd.PurchaseInvoices.FirstOrDefault(x => x.PINo == jd.PurchaseInvoice.PINo);
                }

            }
        }
    }
   
}